package com.haixiaoke.saas.repository.electronicVisa.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasc.open.api.bean.base.BaseRes;
import com.fasc.open.api.bean.common.Actor;
import com.fasc.open.api.bean.common.ActorCorpMember;
import com.fasc.open.api.bean.common.OpenId;
import com.fasc.open.api.enums.common.ActorPermissionEnum;
import com.fasc.open.api.enums.common.IdTypeEnum;
import com.fasc.open.api.enums.corp.CorpAuthScopeEnum;
import com.fasc.open.api.enums.doc.FileTypeEnum;
import com.fasc.open.api.enums.signtask.SignerVerifyMethodsEnum;
import com.fasc.open.api.exception.ApiException;
import com.fasc.open.api.utils.ResultUtil;
import com.fasc.open.api.v5_1.client.*;
import com.fasc.open.api.v5_1.req.corp.CorpIdentInfoReq;
import com.fasc.open.api.v5_1.req.corp.GetCorpAuthResourceUrlReq;
import com.fasc.open.api.v5_1.req.corp.OprIdentInfoReq;
import com.fasc.open.api.v5_1.req.org.GetEntityListReq;
import com.fasc.open.api.v5_1.req.org.GetMemberListFilter;
import com.fasc.open.api.v5_1.req.org.GetMemberListReq;
import com.fasc.open.api.v5_1.req.signtask.*;
import com.fasc.open.api.v5_1.req.template.GetSignTemplateListReq;
import com.fasc.open.api.v5_1.req.template.GetTemplatePreviewUrlReq;
import com.fasc.open.api.v5_1.req.template.SignTemplateDetailReq;
import com.fasc.open.api.v5_1.req.template.SignTemplateListFilterInfo;
import com.fasc.open.api.v5_1.res.common.ECorpAuthUrlRes;
import com.fasc.open.api.v5_1.res.org.EmployeeInfo;
import com.fasc.open.api.v5_1.res.org.GetEntityListRes;
import com.fasc.open.api.v5_1.res.org.GetMemberListRes;
import com.fasc.open.api.v5_1.res.signtask.CreateSignTaskRes;
import com.fasc.open.api.v5_1.res.signtask.GetSignTaskPreviewUrlRes;
import com.fasc.open.api.v5_1.res.signtask.OwnerDownloadUrlRes;
import com.fasc.open.api.v5_1.res.signtask.SignTaskActorGetUrlRes;
import com.fasc.open.api.v5_1.res.template.GetTemplatePreviewUrlRes;
import com.fasc.open.api.v5_1.res.template.SignTemplateDetailRes;
import com.fasc.open.api.v5_1.res.template.SignTemplateListInfo;
import com.fasc.open.api.v5_1.res.template.SignTemplateListRes;
import com.haixiaoke.saas.repository.electronicVisa.api.FadadaBaseUtil;
import com.haixiaoke.saas.repository.electronicVisa.pojo.ElectronicVisaContract;
import com.haixiaoke.saas.repository.exception.BizException;
import com.haixiaoke.saas.repository.pojo.ElectronicSigningContract;
import com.haixiaoke.saas.repository.pojo.OrgElectronicVisa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @author qixi
 * @date 2024/1/24
 */
@Service
public class FadadaElectronicVisaService extends FadadaBaseUtil {
    private CorpClient corpClient;
    private OrgClient orgClient;
    private TemplateClient templateClient;
    private SignTaskClient signTaskClient;

    @Autowired
    private FadadaBaseUtil baseDemo;

    /**
     * 法大大主账号openId
     */
    @Value("${electronicVisa.fadada.mainOpenId}")
    private String mainOpenId;

    /**
     * 免验证签场景码
     */
    @Value("${electronicVisa.fadada.exemptCode}")
    private String exemptCode;

    /**
     * 小程序重定向地址
     */
    private String redirectMiniUrl = "/pages/componentsB/electronicContract/electronicContract";





    public void initClient() {
        try {
            openApiClient = baseDemo.getClient();
            corpClient = new CorpClient(openApiClient);
            orgClient = new OrgClient(openApiClient);
            templateClient = new TemplateClient(openApiClient);
            signTaskClient = new SignTaskClient(openApiClient);
            // 获取应用accessToken
            accessToken = baseDemo.getAccessToken(openApiClient);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * 获取企业用户授权链接
     *
     * @throws Exception
     */
    public String getCorpAuthUrl(String clientCorpId, String mobile) {
        initClient();
        GetCorpAuthResourceUrlReq req = new GetCorpAuthResourceUrlReq();
        req.setAccessToken(accessToken);
        // 企业在应用中的唯一标识
        req.setClientCorpId(clientCorpId);
        // 经办人个人用户的法大大帐号，仅限手机号或邮箱
        req.setAccountName(mobile);
        CorpIdentInfoReq corpIdentInfoReq = new CorpIdentInfoReq();
        req.setCorpIdentInfo(corpIdentInfoReq);
        // 不可修改的企业信息，如不传则表示都可修改。CorpNonEditableInfo枚举值
        List<String> corpNonEditableInfo = new ArrayList<>();
        req.setCorpNonEditableInfo(corpNonEditableInfo);
        //（可选）企业授权范围列表CorpAuthScopeEnum
        req.setAuthScopes(Arrays.asList(CorpAuthScopeEnum.IDENT_INFO.getCode(),
                CorpAuthScopeEnum.SIGN_TASK_INIT.getCode(),
                CorpAuthScopeEnum.SIGN_TASK_INFO.getCode(),
                CorpAuthScopeEnum.SIGN_TASK_FILE.getCode(),
                CorpAuthScopeEnum.SEAL_INFO.getCode(),
                CorpAuthScopeEnum.ORGANIZATION.getCode(),
                CorpAuthScopeEnum.TEMPLATE.getCode()));
        //（可选）重定向地址。
        // req.setRedirectUrl("http://www.baidu.com");

        OprIdentInfoReq oprIdentInfo = new OprIdentInfoReq();
        List<String> oprIdentMethod = new ArrayList<>();
        oprIdentMethod.add("face");
        oprIdentInfo.setOprIdentMethod(oprIdentMethod);
        req.setOprIdentInfo(oprIdentInfo);

        try {
            BaseRes<ECorpAuthUrlRes> res = corpClient.getCorpAuthUrl(req);
            String code = res.getCode();
            if (!"100000".equals(code)) {
                throw new BizException(res.getMsg());
            }
            return res.getData().getAuthUrl();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询企业信息
     */
    public List<GetEntityListRes> getCorpEntityList(String openCorpId) throws ApiException {
        initClient();
        GetEntityListReq req = new GetEntityListReq();
        req.setAccessToken(accessToken);
        req.setOpenCorpId(openCorpId);
        BaseRes<List<GetEntityListRes>> corpEntityList = orgClient.getCorpEntityList(req);
        String code = corpEntityList.getCode();
        if ("100000".equals(code)) {
            List<GetEntityListRes> data = corpEntityList.getData();
            return data;
        } else {
            throw new BizException(corpEntityList.getMsg());
        }
    }

    /**
     * 查询签署模板列表
     *
     * @throws ApiException
     */
    public List<SignTemplateListInfo> signTempalteList() throws ApiException {
        initClient();
        GetSignTemplateListReq signTemplateListReq = new GetSignTemplateListReq();
        signTemplateListReq.setAccessToken(accessToken);
        //（可选）模板归属方,主体类型IdTypeEnum。如果指定，则表示查询企业主体的模板。如果未指定，则表示查询应用的模板。
        // signTemplateListReq.setOwnerId(OpenId.getInstance(IdTypeEnum.CORP.getCode(), openCorpId));
        //（可选）查询条件
        SignTemplateListFilterInfo signTemplateListFilterInfo = new SignTemplateListFilterInfo();
        // 签署模板名称关键字
        signTemplateListReq.setListFilter(signTemplateListFilterInfo);
        //（可选）查询结果分页返回，此处指定第几页，如果不传默从第一页返回。页码从1开始，即首页为1
        signTemplateListReq.setListPageNo(1);
        //（可选）指定每页多少条数据，如果不传默认为100，单页最大100
        signTemplateListReq.setListPageSize(100);
        BaseRes<SignTemplateListRes> signTemplateListResBaseRes = templateClient.getSignTemplateList(signTemplateListReq);
        String code = signTemplateListResBaseRes.getCode();
        if ("100000".equals(code)) {
            SignTemplateListRes data = signTemplateListResBaseRes.getData();
            return data.getSignTemplates();
        } else {
            throw new BizException(signTemplateListResBaseRes.getMsg());
        }
    }

    /**
     * 获取签署模板详情
     *
     * @throws ApiException
     */
    public SignTemplateDetailRes signTempalteDetail(String signTemplateId) throws ApiException {
        initClient();
        SignTemplateDetailReq signTemplateDetailReq = new SignTemplateDetailReq();
        signTemplateDetailReq.setAccessToken(accessToken);
        //（可选）模板归属方，主体类型IdTypeEnum。如果未指定，则表示查询应用的模板。如果指定，则表示查询企业主体有权访问的模板（主体模板和应用模板）
        // 签署模板Id
        signTemplateDetailReq.setSignTemplateId(signTemplateId);
        BaseRes<SignTemplateDetailRes> signTemplateDetailResBaseRes = templateClient.getSignTemplateDetail(signTemplateDetailReq);
        String code = signTemplateDetailResBaseRes.getCode();
        if ("100000".equals(code)) {
            return signTemplateDetailResBaseRes.getData();
        } else {
            throw new BizException(signTemplateDetailResBaseRes.getMsg());
        }

    }

    /**
     * 获取模板预览地址
     *
     * @throws ApiException
     */
    public String getTemplatePreviewUrl(String templateId, OrgElectronicVisa electronicVisa) throws ApiException {
        initClient();
        GetTemplatePreviewUrlReq getTemplatePreviewUrlReq = new GetTemplatePreviewUrlReq();
        // 法大大平台为该企业在该应用appId范围内分配的唯一标识
        getTemplatePreviewUrlReq.setOpenCorpId(mainOpenId);
        // 模板id 可以文档模板ID,或者签署模板ID
        getTemplatePreviewUrlReq.setTemplateId(templateId);
        // 重定向地址
        // getTemplatePreviewUrlReq.setRedirectUrl("http://www.baidu.com");
        getTemplatePreviewUrlReq.setAccessToken(accessToken);

        BaseRes<GetTemplatePreviewUrlRes> res = templateClient.getTemplatePreviewUrl(getTemplatePreviewUrlReq);
        if ("100000".equals(res.getCode())) {
            return res.getData().getTemplatePreviewUrl();
        } else {
            throw new BizException(res.getMsg());
        }
    }

    /**
     * 创建签署任务
     *
     * @throws ApiException
     */
    public String  createWithTemplate(ElectronicVisaContract bean) throws ApiException {
        initClient();
        OrgElectronicVisa orgElectronicVisa = bean.getOrgElectronicVisa();

        CreateWithTemplateReq createWithTemplateReq = new CreateWithTemplateReq();
        createWithTemplateReq.setAccessToken(accessToken);
        // 该签署任务的发起方。
        createWithTemplateReq.setInitiator(OpenId.getInstance(IdTypeEnum.CORP.getCode(), orgElectronicVisa.getOpenId()));
        // 签署任务主题。长度最大100个字符。
        createWithTemplateReq.setSignTaskSubject("房屋租赁合同");
        // 指定签署模板ID。 法大大平台将从该签署模板中复制预先设定的文档、控件和签署方，并对每个签署方指定具体的用户或企业。
        createWithTemplateReq.setSignTemplateId(bean.getTemplateId());
        //（可选）任务过期时间。
        Date time = bean.getExpiresTime();
        if (ObjectUtil.isNotNull(time)){
            long time1 = time.getTime();
            createWithTemplateReq.setExpiresTime(StrUtil.toString(time1));
        }
        //（可选）签署任务是否自动发起协作流程：false: 不自动发起 true: 自动发起 默认为false。
        createWithTemplateReq.setAutoStart(true);
        //（可选）全部必填控件填写完成后是否自动定稿：false: 不自动定稿 true: 自动定稿 默认为true。
        createWithTemplateReq.setAutoFillFinalize(true);
        //（可选）您的业务应用系统中的业务场景信息，用于更好地定义业务场景和签署任务的关系。
        createWithTemplateReq.setBusinessId(exemptCode);


        //（可选）参与方列表。
        createWithTemplateReq.setActors(getSignTemplateActors(bean));

        System.out.println(openApiClient.getJsonStrategy().toJson(createWithTemplateReq));
        BaseRes<CreateSignTaskRes> res = signTaskClient.createWithTemplate(createWithTemplateReq);
        if ("100000".equals(res.getCode())) {
            return res.getData().getSignTaskId();
        } else {
            throw new BizException(res.getMsg());
        }
    }

    /**
     * 签署任务--签署模板的参与方列表
     */
    private static List<AddActorsTempInfo> getSignTemplateActors(ElectronicVisaContract bean) throws ApiException {
        List<AddActorsTempInfo> addActors = new ArrayList<>();

        // 参与方一：个人参与方
        // 参与方标识：需要与签署模板中保持一致
        String actorId = "个人方";
        // 参与方具体名称
        String actorName = "个人方名称";
        //（可选）参与方主体在应用上的OpenId
        String actorOpenId = null;
        //（可选）参与方主体的法大大号
        String actorFDDId = null;
        //（可选）参与方身份名称匹配信息
        String identNameForMatch = bean.getName();
        //（可选）参与方证件号码匹配信息
        String certNoForMatch = bean.getIdCard();
        //（可选）法大大送达信息
        // Notification notification = Notification.getInstance(true, NotifyWayEnum.MOBILE.getCode(), mobile);
        Actor person = getActor(actorId, IdTypeEnum.PERSON.getCode(), actorName, null,
                actorOpenId, actorFDDId,
                null, identNameForMatch, certNoForMatch,
                null
        );
        person.setSendNotification(false);

        //（可选）签署权限参与方关联的签章控件列表。
        // List<AddSignFieldInfo> signFields = new ArrayList<>();
        // AddSignFieldInfo addSignFieldInfo = getAddSignFieldInfo(TemplateFieldDocId, "个人签署控件编码", "个人签署控件名称", null,true);
        // signFields.add(addSignFieldInfo);

        //（可选）签署权限参与方的签署配置信息
        TemplateSignConfigInfoReq signConfigInfo = new TemplateSignConfigInfoReq();
        //(可选）参与方签署序号
        signConfigInfo.setOrderNo(1);
        //（可选）个人参与方或企业参与方经办人的签署方式
        signConfigInfo.setSignerSignMethod(null);
        //（可选）是否要求该参与方将所有文档（不包含附件）阅读至末页才可签署
        signConfigInfo.setReadingToEnd(null);
        //（可选）要求该参与方的最少阅读时间，单位为秒
        signConfigInfo.setReadingTime(null);
        //（可选）允许该参与方使用的身份和意愿确认方式
        ArrayList<String> verifyMethods = new ArrayList<>();
        verifyMethods.add(SignerVerifyMethodsEnum.FACE.getCode());
        signConfigInfo.setVerifyMethods(verifyMethods);
        //（可选）企业参与方成员能否通过链接打开签署任务
        signConfigInfo.setJoinByLink(true);
        //（可选）是否暂时阻塞
        signConfigInfo.setBlockHere(false);
        //（可选）是否请求该参与方免验证签
        signConfigInfo.setRequestVerifyFree(false);
        //（可选）要求该参与方必须实名才能查看签署任务，默认true
        signConfigInfo.setIdentifiedView(false);

        AddActorsTempInfo addPerson = new AddActorsTempInfo();
        addPerson.setActor(person);
        addPerson.setSignConfigInfo(signConfigInfo);
        addActors.add(addPerson);

        // 参与方二：企业参与方
        // actorId必须与签署模板中保持一致，actorType和permission以签署模板中为准，不用传参。
        //（可选）参与方企业成员列表
        ActorCorpMember actorCorpMember = new ActorCorpMember();

        OrgElectronicVisa orgElectronicVisa = bean.getOrgElectronicVisa();
        actorCorpMember.setMemberId(orgElectronicVisa.getProxyOperatorOpenid());

        // 通知方式
        // Notification notification1 =  Notification.getInstance(false, NotifyWayEnum.MOBILE.getCode(), mobile);

        Actor corp = getActor("企业方", IdTypeEnum.CORP.getCode(), orgElectronicVisa.getOrganizationName(), new String[]{ActorPermissionEnum.SIGN.getCode(), ActorPermissionEnum.FILL.getCode()},
                orgElectronicVisa.getOpenId(), null, new ActorCorpMember[]{actorCorpMember}
                , null, null,
                null
        );
        corp.setSendNotification(false);

        // //（可选）签署权限参与方关联的签章控件列表。
        // List<AddSignFieldInfo> signFields2 = new ArrayList<>();
        // AddSignFieldInfo addSignFieldInfo2 = getAddSignFieldInfo(TemplateFieldDocId, "企业签署控件编码", "企业签署控件名称", null,true);
        // signFields2.add(addSignFieldInfo2);

        // 签署权限参与方的签署配置信息
        TemplateSignConfigInfoReq signConfigInfo1 = new TemplateSignConfigInfoReq();
        //（可选）是否暂时阻塞
        signConfigInfo1.setBlockHere(false);
        //（可选）是否请求该参与方免验证签
        signConfigInfo1.setRequestVerifyFree(true);
        signConfigInfo1.setVerifyMethods(verifyMethods);


        List<AddFillFieldInfo> fillFields = new ArrayList<>(bean.getFillFieldList());

        AddActorsTempInfo addCorp = new AddActorsTempInfo();
        addCorp.setActor(corp);
        addCorp.setSignConfigInfo(signConfigInfo1);
        addCorp.setFillFields(fillFields);
        addActors.add(addCorp);
        return addActors;
    }

    /**
     * 查询企业成员列表
     *
     * @throws ApiException
     */
    public List<EmployeeInfo> getCorpMemberList(OrgElectronicVisa orgElectronicVisa) throws ApiException {
        initClient();
        GetMemberListReq req = new GetMemberListReq();
        req.setAccessToken(accessToken);
        // 法大大平台为该企业在该应用appId范围内分配的唯一标识。
        req.setOwnerId(orgElectronicVisa.getOpenId());
        //（可选）查询条件
        GetMemberListFilter filter = new GetMemberListFilter();
        // 部门Id
        filter.setDeptId(null);
        // 如果为true，则同时获取其所有子部门员工; 如果为false或者不传，则只获取当前部门员工,默认为true
        filter.setFetchChild(true);
        // 角色类型，如传该字段，表示查询该角色的成员,目前只支持super_admin：超级管理员；如不传，表示查询所有成员
        filter.setRoleType("super_admin");
        req.setListFilter(filter);
        //（可选）查询结果分页返回，此处指定第几页，如果不传默从第一页返回。页码从1开始，即首页为1
        req.setListPageNo(1);
        //（可选）指定每页多少条数据，如果不传默认为100，单页最大100
        req.setListPageSize(100);
        BaseRes<GetMemberListRes> res = orgClient.getMemberList(req);
        if ("100000".equals(res.getCode())) {
            List<EmployeeInfo> employeeInfos = res.getData().getEmployeeInfos();
            return employeeInfos;
        } else {
            throw new BizException(res.getMsg());
        }
    }

    /**
     * 获取签署任务预览链接
     *
     * @throws ApiException
     */
    public String getSignTaskPreviewUrl(String flowId) throws ApiException {
        initClient();
        GetSignTaskUrlReq getSignTaskUrlReq = new GetSignTaskUrlReq();
        // 重定向地址
        // getSignTaskUrlReq.setRedirectUrl("http://www.baidu.com");
        // 签署任务ID
        getSignTaskUrlReq.setSignTaskId(flowId);
        getSignTaskUrlReq.setAccessToken(accessToken);

        BaseRes<GetSignTaskPreviewUrlRes> res = signTaskClient.getSignTaskPreviewUrl(getSignTaskUrlReq);
        if ("100000".equals(res.getCode())) {
            return res.getData().getSignTaskPreviewUrl();
        } else {
            throw new BizException(res.getMsg());
        }
    }


    public String getActorUrl(ElectronicSigningContract electronicSigningContract, Integer loginType) throws ApiException {
        initClient();
        SignTaskActorGetUrlReq signTaskActorGetUrlReq = new SignTaskActorGetUrlReq();
        // 参与方在签署任务中被设定的唯一标识
        if (loginType == 1) {
            signTaskActorGetUrlReq.setActorId("企业方");
        } else {
            signTaskActorGetUrlReq.setActorId("个人方");
            signTaskActorGetUrlReq.setRedirectMiniAppUrl(this.redirectMiniUrl);
        }
        // 应用系统中唯一确定登录用户身份的标识，如应用系统中该用户标识和法大大的账号存在映射关系，则可以实现免登进入签署页面进行签署
        // signTaskActorGetUrlReq.setClientUserId(clientUserId);

        // 重定向地址

        // 签署任务ID
        signTaskActorGetUrlReq.setSignTaskId(electronicSigningContract.getFlowId());
        signTaskActorGetUrlReq.setAccessToken(accessToken);

        BaseRes<SignTaskActorGetUrlRes> res = signTaskClient.signTaskActorGetUrl(signTaskActorGetUrlReq);
        if ("100000".equals(res.getCode())) {
            return res.getData().getActorSignTaskEmbedUrl();
        } else {
            throw new BizException(res.getMsg());
        }
    }

    /**
     * 获取指定归属方的签署任务文档下载地址
     *
     * @throws ApiException
     */
    public  String getOwnerDownloadUrl(ElectronicSigningContract electronicSigningContract,String openCorpId) throws ApiException {
        initClient();
        GetOwnerDownloadUrlReq req = new GetOwnerDownloadUrlReq();
        req.setAccessToken(accessToken);
        //签署任务发起方或参与方
        req.setOwnerId(OpenId.getInstance(IdTypeEnum.CORP.getCode(), openCorpId));
        //签署任务id，通过创建签署任务接口返回
        req.setSignTaskId(electronicSigningContract.getFlowId());
        //（可选）文档类型FileTypeEnum：doc：签署任务中的文档 。 attach：签署任务中的附件。
        // req.setFileType(FileTypeEnum.DOC.getCode());
        //（可选）指定签署任务中的文档序号docId或附件序号attachId。
        // req.setId("1");
        req.setFolderBySigntask(false);
        req.setCompression(true);
        req.setCustomName("房屋租赁合同_" + DateUtil.now());
        BaseRes<OwnerDownloadUrlRes> res = signTaskClient.getOwnerDownloadUrl(req);
        if ("100000".equals(res.getCode())) {
            return res.getData().getDownloadUrl();
        } else {
            throw new BizException(res.getMsg());
        }
    }

    /**
     * 撤销签署任务
     *
     * @throws ApiException
     */
    public  void cancel(ElectronicSigningContract electronicSigningContract) throws ApiException {
        initClient();
        SignTaskCancelReq signTaskBaseReq = new SignTaskCancelReq();
        signTaskBaseReq.setAccessToken(accessToken);
        //签署任务id，通过创建签署任务接口返回
        signTaskBaseReq.setSignTaskId(electronicSigningContract.getFlowId());
        BaseRes<Void> res = signTaskClient.cancel(signTaskBaseReq);
        if (!"100000".equals(res.getCode())) {
            throw new BizException(res.getMsg());
        }
    }


}
